#include "IShader.h"

IShader::IShader(void)
{
	g_pGeometricShader = NULL;
	g_pPixelShader = NULL;
	g_pVertexShader = NULL;
}

IShader::~IShader(void)
{
}

///"vs_4_0"
///"ps_4_0"
///"gs_4_0"
HRESULT IShader::Init(const char* effectName,const char* VsName, const char* vsVersion, const char* PsName,const char* psVersion, VertexLayout vl, const char* GsName ,const char* GsVersion , D3D11_SO_DECLARATION_ENTRY declaration[] , int nElements ,UINT* stride , UINT numStrides)
{
	HRESULT hr = S_OK;
	// Compile the vertex shader
    ID3DBlob* pVSBlob = NULL;
    hr = CompileShaderFromFile( effectName, VsName, vsVersion, &pVSBlob );
	CheckError(hr);
	
    // Create the vertex shader
	hr = EngineStuff::EGraphicsDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader );
    if( FAILED( hr ) )
    {    
        pVSBlob->Release();
        return hr;
    }	

    // Create the input layout
	hr = EngineStuff::EGraphicsDevice->CreateInputLayout(vl.Layout , vl.NumElements, pVSBlob->GetBufferPointer(),
                                          pVSBlob->GetBufferSize(), &g_pVertexLayout );
    pVSBlob->Release();
    CheckError(hr);

	if(GsName!= NULL)
	{
		// Compile the Geometry shader
		ID3DBlob* pGSBlob = NULL;
		hr = CompileShaderFromFile( effectName, GsName, GsVersion, &pGSBlob  );		
		CheckError(hr);

		if(declaration != NULL)
		{
			// Create the Geometry shader
			hr = EngineStuff::EGraphicsDevice->CreateGeometryShaderWithStreamOutput( pGSBlob->GetBufferPointer(), pGSBlob->GetBufferSize(), declaration,nElements, stride ,numStrides,0,NULL, &g_pGeometricShader);
			if( FAILED( hr ) )
			{    
				pGSBlob->Release();
				return hr;
			}
		}
		else
		{
			// Create the Geometry shader
			hr = EngineStuff::EGraphicsDevice->CreateGeometryShader( pGSBlob->GetBufferPointer(), pGSBlob->GetBufferSize(), NULL, &g_pGeometricShader);
			if( FAILED( hr ) )
			{    
				pVSBlob->Release();
				return hr;
			}
		}
	}


	if(PsName != NULL)
	{
		// Compile the pixel shader
		ID3DBlob* pPSBlob = NULL;
		hr = CompileShaderFromFile( effectName, PsName, psVersion, &pPSBlob );
		CheckError(hr);
	    
		// Create the pixel shader
		hr = EngineStuff::EGraphicsDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader );
		pPSBlob->Release();
		CheckError(hr);	
	}

	return hr;

}

void IShader::SetShaderOnDevice(RenderableObject obj)
{
	EngineStuff::EImediateDeviceContext->IASetInputLayout( g_pVertexLayout );
	EngineStuff::EImediateDeviceContext->VSSetShader( g_pVertexShader, NULL, 0 );    
    EngineStuff::EImediateDeviceContext->PSSetShader( g_pPixelShader, NULL, 0 );
	EngineStuff::EImediateDeviceContext->GSSetShader( g_pGeometricShader , NULL, 0 );
}


//--------------------------------------------------------------------------------------
// Helper for compiling shaders with D3DX11
//--------------------------------------------------------------------------------------
HRESULT IShader::CompileShaderFromFile( const char* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut )
{
    HRESULT hr = S_OK;

    DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
    // Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
    // Setting this flag improves the shader debugging experience, but still allows 
    // the shaders to be optimized and to run exactly the way they will run in 
    // the release configuration of this program.
    dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif

    ID3DBlob* pErrorBlob;
    hr = D3DX11CompileFromFile( szFileName, NULL, NULL, szEntryPoint, szShaderModel, 
        dwShaderFlags, 0, NULL, ppBlobOut, &pErrorBlob, NULL );
    if( FAILED(hr) )
    {

#ifdef _DEBUG
        if( pErrorBlob != NULL )
            OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() );			
			MessageBox(NULL,(char*)pErrorBlob->GetBufferPointer() ,"ERROR",MB_OK );
#endif
        if( pErrorBlob ) pErrorBlob->Release();
        return hr;
    }
    if( pErrorBlob ) pErrorBlob->Release();

    return S_OK;
}

